﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DoeObjects;
using System.Collections.Generic;

namespace DoeLibsTest
{
    [TestClass]
    public class User_Test
    {
        [TestInitialize]
        public void init()
        {
            TestContext.initialize();
        }

        [TestMethod]
        public void test_getUserByCategoryWithId()
        {
            User u1_staff = Helper.createUserObject(true, true);
            User u2_staff = Helper.createUserObject(true, true);
            User u3_student = Helper.createUserObject(false, true);

            if (u1_staff != null && u2_staff != null && u3_student != null)
            {
                List<User> staffUsers = User.getUsersOfCategory(1);
                List<User> studentUsers = User.getUsersOfCategory(2);

                Assert.IsTrue(staffUsers.Count >= 2);
                Assert.IsTrue(staffUsers.Count >= 1);

                foreach (User user in staffUsers)
                {
                    Assert.AreEqual(1, user.Category.CategoryId);
                }

                foreach (User user in studentUsers)
                {
                    Assert.AreEqual(2, user.Category.CategoryId);
                }
            }
            else
            {
                Assert.Fail("could not setup users");
            }
        }

        [TestMethod]
        public void test_getUserByCategoryWithName()
        {
            User u1_staff = Helper.createUserObject(true, true);
            User u2_staff = Helper.createUserObject(true, true);
            User u3_student = Helper.createUserObject(false, true);

            if (u1_staff != null && u2_staff != null && u3_student != null)
            {
                List<User> staffUsers = User.getUsersOfCategory("Staff");
                List<User> studentUsers = User.getUsersOfCategory("Student");

                Assert.IsTrue(staffUsers.Count >= 2);
                Assert.IsTrue(staffUsers.Count >= 1);

                foreach (User user in staffUsers)
                {
                    Assert.AreEqual(1, user.Category.CategoryId);
                }

                foreach (User user in studentUsers)
                {
                    Assert.AreEqual(2, user.Category.CategoryId);
                }
            }
            else
            {
                Assert.Fail("could not setup users");
            }
        }

        [TestMethod]
        public void test_getUserByCategoryWithObject()
        {
            User u1_staff = Helper.createUserObject(true, true);
            User u2_staff = Helper.createUserObject(true, true);
            User u3_student = Helper.createUserObject(false, true);

            UserCategory staffCat = UserCategory.getById(1);
            UserCategory studentCat = UserCategory.getById(2);

            if (u1_staff != null && u2_staff != null && u3_student != null && staffCat != null && studentCat != null)
            {
                List<User> staffUsers = User.getUsersOfCategory(staffCat);
                List<User> studentUsers = User.getUsersOfCategory(studentCat);

                Assert.IsTrue(staffUsers.Count >= 2);
                Assert.IsTrue(staffUsers.Count >= 1);

                foreach (User user in staffUsers)
                {
                    Assert.AreEqual(1, user.Category.CategoryId);
                }

                foreach (User user in studentUsers)
                {
                    Assert.AreEqual(2, user.Category.CategoryId);
                }
            }
            else
            {
                Assert.Fail("could not setup environment");
            }
        }

        [TestMethod]
        public void test_getUserMail()
        {
            User u = Helper.createUserObject(false, true);

            Assert.IsTrue(u != null, "could not setup userobject");

            string userMail = User.getUserMail(u.UserId);

            Assert.AreEqual(u.EMail, userMail);
        }


        [TestMethod]
        public void test_activateUser()
        {
            User u = Helper.createUserObject(false, false);
            User activator = Helper.createUserObject(true, true);

            Assert.IsTrue(activator != null, "could not save activator");

            u.Acceptor = activator;

            Assert.IsTrue(u.save(), "could not save user");

            Assert.IsTrue(User.activateUser(u.UserId), "could not activate user");

            User activatedUser = User.getUserByUserId(u.UserId);
            Assert.IsNull(activatedUser.Acceptor, "acceptor is not null");
        }

		[TestMethod]
		public void test_expireUserStudent()
		{
			// Setting up mail for now.
			Settings.UseMailQueueing = false;
			Settings.SimpleMailClient = new System.Net.Mail.SmtpClient
			{
				Host = "smtp.gmail.com",
				Port = Convert.ToInt32("587"),
				Credentials = new System.Net.NetworkCredential(
					"noreply.doelibs@gmail.com",
					"4abRuthe"),
				DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network,
				EnableSsl = true
			};
			Settings.SenderAddress = new System.Net.Mail.MailAddress("noreply.doelibs@gmail.com", "Doelibs");

			User user1 = Helper.createUserObject();
			//user1.EMail = "testForNowYees5@gmail.come";//Helper.getRandomString().Substring(0, 10) + "@" + Helper.getRandomString().Substring(0, 10) + ".come";
			Assert.IsTrue(user1.save(), "Could not save user");

			Assert.IsTrue(user1.Activated == true, "Activated property is not set on user creation");
			Assert.IsTrue(user1.ExpireNotificationSent == false, "ExpireNotificaionSent property is not set on user creation");
			Assert.IsTrue(user1.IsPendingExpiration == false, "IsPendingExpiration is not working");
			Assert.IsTrue(user1.RegistrationDate.Date == DateTime.Now.Date, "RegistrationDate is not set to today");
			Assert.IsTrue(user1.UserExpirationDate.Value.Date == user1.RegistrationDate.Date.AddYears(3), "UserExpirationDate is not set to 3 years after registration date");

			user1.RegistrationDate = new DateTime(2012, 08, 30);
			user1.UserExpirationDate = DateTime.Now.Date.AddDays(20);
			Assert.IsTrue(user1.save(), "Could not save user");

			User userFromDb = User.getUserByUserId(user1.UserId);

			Assert.IsTrue(userFromDb.Activated == true, "Activated property is wrong");
			Assert.IsTrue(userFromDb.ExpireNotificationSent == false, "ExpireNotificaionSent property is wrong");
			Assert.IsTrue(userFromDb.IsPendingExpiration == false, "IsPendingExpiration is not working");
			Assert.IsTrue(userFromDb.RegistrationDate.Date == new DateTime(2012, 08, 30).Date, "RegistrationDate is not set correctly during save");
			Assert.IsTrue(userFromDb.UserExpirationDate.Value.Date == DateTime.Now.Date.AddDays(20), "UserExpirationDate is not set correctly during save");

			Loanable loanable = Helper.createLoanable(true);
			Loanable loanable2 = Helper.createLoanable(true);
			Assert.IsTrue(loanable.Status == Status.AVAILABLE && loanable2.Status == Status.AVAILABLE, "Test will fail, new loanable is not available");
			Loan loan = loanable.checkOut(userFromDb);
			Reservation.createReservation(loanable2.Title.TitleId, userFromDb.UserId);
			Assert.IsTrue(Loan.getActiveLoansFromUser(userFromDb.UserId).Count == 1, "Check out of loanable was not made");
			Assert.IsTrue(Reservation.getReservationsByUser(userFromDb.UserId).Count == 1, "Reservation was not set");

			foreach (Notification nots in Notification.getAllForUser(userFromDb.UserId))
				Notification.delete(nots.NotificationId);
			Assert.IsTrue(Notification.getAllForUser(userFromDb.UserId).Count == 0, "Notification test when testing expire user will fail, could not clear nots");

			User.handleExpiredUsers();

			userFromDb = User.getUserByUserId(userFromDb.UserId);

			Assert.IsTrue(userFromDb.ExpireNotificationSent == true, "Notification should have been sent to about to expire user");
			Assert.IsTrue(Notification.getAllForUser(userFromDb.UserId).Count != 0, "Notification was not sent to about to expire user");

			userFromDb.UserExpirationDate = DateTime.Now.Date;
			userFromDb.save();
			User.handleExpiredUsers();

			Assert.IsTrue(Reservation.getReservationsByUser(userFromDb.UserId).Count == 0, "Reservations does not get deleted");
			Loan usersLoan = Loan.getActiveLoansFromUser(userFromDb.UserId)[0];
			Assert.IsTrue(usersLoan.ReasonForRecall.Value == RecallReason.USER_EXPIRE, "Loan was not recalled");
			Assert.IsTrue(userFromDb.IsPendingExpiration == true, "IsPendingExpiration seems to not work");
			usersLoan.checkIn();
			Assert.IsTrue(Loan.getActiveLoansFromUser(userFromDb.UserId).Count == 0, "Loan did not get checked in and active loans return != 0");

			User.handleExpiredUsers();

			userFromDb = User.getUserByUserId(userFromDb.UserId);
			Assert.IsTrue(userFromDb.Activated == false, "User does not get deactivated when expiring");
		}

		[TestMethod]
		public void test_renewUser()
		{
			User user1 = Helper.createUserObject();
			user1.save();
			user1 = User.getUserByUserId(user1.UserId);

			DateTime time1 = user1.UserExpirationDate.Value.Date;
			user1.renewExpirationDate();
			Assert.IsTrue(time1.AddYears(3) == user1.UserExpirationDate.Value.Date, "Users expiration date was not renewed correctly");
		}

		[TestMethod]
		public void test_expireUserDirectly()
		{
			User user1 = Helper.createUserObject();
			user1.Category = UserCategory.getById(1); // staff
			user1.save();
			User userFromDb = User.getUserByUserId(user1.UserId);

			Assert.IsTrue(!userFromDb.UserExpirationDate.HasValue, "Staff member got expiration date");

			Loanable loanable = Helper.createLoanable(true);
			Loanable loanable2 = Helper.createLoanable(true);
			Assert.IsTrue(loanable.Status == Status.AVAILABLE && loanable2.Status == Status.AVAILABLE, "Test will fail, new loanable is not available");
			Loan loan = loanable.checkOut(userFromDb);
			Reservation.createReservation(loanable2.Title.TitleId, userFromDb.UserId);
			Assert.IsTrue(Loan.getActiveLoansFromUser(userFromDb.UserId).Count == 1, "Check out of loanable was not made");
			Assert.IsTrue(Reservation.getReservationsByUser(userFromDb.UserId).Count == 1, "Reservation was not set");

			userFromDb.expireUser();
			Assert.IsTrue(Reservation.getReservationsByUser(userFromDb.UserId).Count == 0, "Reservation was not deleted");
			loan = Loan.getActiveLoansFromUser(userFromDb.UserId)[0];
			Assert.IsTrue(loan.ReasonForRecall == RecallReason.USER_EXPIRE, "Loan was not recalled");
			Assert.IsTrue(userFromDb.Activated == true, "Account is not active");

			loan.checkIn();
			User.handleExpiredUsers();
			userFromDb = User.getUserByUserId(userFromDb.UserId);
			Assert.IsTrue(userFromDb.Activated == false, "Account was not set to deleted (Activated == false)");

			User user2 = Helper.createUserObject();
			user2.Category = UserCategory.getById(1); // staff
			user2.save();
			user2.expireUser();
			userFromDb = User.getUserByUserId(user2.UserId);
			Assert.IsTrue(userFromDb.Activated == false, "\"Empty\" account was not set to deleted (Activated == false)");

			// Add tests for loanables :P
		}
    }
}
